/*
 * Copyright 2011 Alibaba.com All right reserved. This software is the
 * confidential and proprietary information of Alibaba.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with Alibaba.com.
 */
package com.whale.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.media.FaceDetector;
import android.os.Environment;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;


/**
 * 
 * @author christ.yuj
 */
public class PicView extends View implements OnGestureListener{

	private GestureDetector mGd;   //手势识别
	
    private static final int		NUM_FACES      = 10;                              // max is 64
    private static final boolean	DEBUG          = true;
    
    private FaceDetector      	arrayFaces;
    private FaceDetector.Face 	getAllFaces[]  = new FaceDetector.Face[NUM_FACES];
    private FaceDetector.Face 	getFace        = null;

    public PointF             	eyesMidPts[]   = new PointF[NUM_FACES];
    public float             	eyesDistance[] = new float[NUM_FACES];
    public String          		eyesPeopleNames[] = new String[NUM_FACES];

    private Bitmap     			sourceImage;
    
    private Paint				tmpPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Paint               pDefault = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Paint               pMoving = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Paint               pScaling = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Paint               pTextLabel = new Paint(Paint.ANTI_ALIAS_FLAG);
    

    public int                  picWidth, picHeight;
    public float                xRatio, yRatio;
    public float                ratio = 1.0f;
    public float                dx = 0, dy = 0;
    
    private static final int 	NONE = 0;
    private static final int 	DRAG = 1;
    private static final int 	ZOOM = 2;
    private int 				mode = NONE;
    private float 				oldDist = 1.0f;
    private PointF 				startPointF = new PointF();
    private PointF 				endPointF = new PointF();
    private static final 		String TAG = "Touch";
    
    private static final float	MIN_SCALE = 0.25f;
    private static final float	MAX_SCALE = 4.0f;
    private static final int	TITLE_HEIGHT = 50;
    
    private float				scale = 1.0f; //放大缩小
    private Context				context;
    private float				sensitive = 1.0f; //敏感系数 越大缩放变化越大，越小缩放变化越小
    
    public int mActionSelectedIdx = -1;
    public int mActionMoveIdx = -1;
    public int mActionScaleIdx = -1;
    
    public PicView(Context context){
        super(context);
        this.context = context; 
        init();

    }
    
    /**
     * @param context
     * @param attrs
     */
    public PicView(Context context, AttributeSet attrs){
        super(context, attrs);
        this.context = context;
        init();

    }

	private void init() {

		mGd = new GestureDetector(this); //要和UI主线程在一起
		mGd.setIsLongpressEnabled(true); 
		
		
        pScaling.setStyle(Paint.Style.STROKE);
        pScaling.setColor(Color.YELLOW);
        
        pMoving.setStyle(Paint.Style.STROKE);
        pMoving.setColor(Color.RED);

        pDefault.setStyle(Paint.Style.STROKE);
        pDefault.setColor(Color.WHITE);
        
        pTextLabel.setStyle(Paint.Style.FILL);
        pTextLabel.setColor(Color.YELLOW);
        pTextLabel.setTextSize(30);
        
        pDefault.setStrokeWidth(2);
        pScaling.setStrokeWidth(3);
        pMoving.setStrokeWidth(5);
        pTextLabel.setStrokeWidth(1);

        tmpPaint.setStyle(Paint.Style.STROKE);
        tmpPaint.setTextAlign(Paint.Align.CENTER);

        BitmapFactory.Options bfo = new BitmapFactory.Options();
        bfo.inPreferredConfig = Bitmap.Config.RGB_565;

        String pathString = 
            Environment.getExternalStorageDirectory().toString()
            + "/.babylon/picview.jpg";
        sourceImage = BitmapFactory.decodeFile(pathString);
        
        picWidth = sourceImage.getWidth();
        picHeight = sourceImage.getHeight();
        
        // faceDetect(); //人脸识别
        
    }
    
	@Override
    protected void onDraw(Canvas canvas) {
    	
    	toLimitView(MIN_SCALE, MAX_SCALE);
    	
        canvas.drawBitmap(sourceImage, new Rect((int)(0 + dx),(int)(0 + dy),(int)(getWidth()/scale+dx), (int)(getHeight()/scale + dy)), 
                    new Rect(0, 0, getWidth(), getHeight()), tmpPaint);
        
        Paint pTemp1 = pDefault;
        for (int i = 0; i < eyesMidPts.length; i++) {
            if (eyesMidPts[i] != null) {
                if (i == mActionMoveIdx) {
                    pTemp1 = pMoving;
                } else if (i == mActionScaleIdx) {
                    pTemp1 = pScaling;
                } else {
                    pTemp1 = pDefault;
                }
                canvas.drawCircle(toRawCoordinates(eyesMidPts[i].x,eyesMidPts[i].y).x,
                		toRawCoordinates(eyesMidPts[i].x,eyesMidPts[i].y).y, 
                        eyesDistance[i] * 2 *scale,
                        pTemp1);
                
                if (eyesPeopleNames[i] != null) {
                    canvas.drawText(eyesPeopleNames[i],
                    		toRawCoordinates(eyesMidPts[i].x-eyesDistance[i]*2,eyesMidPts[i].y-eyesDistance[i]*2).x,
                    		toRawCoordinates(eyesMidPts[i].x-eyesDistance[i]*2,eyesMidPts[i].y-eyesDistance[i]*2).y,
                            pTextLabel);
                }
                
            }
        }
    }
	
	
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		// TODO Auto-generated method stub
		super.onSizeChanged(w, h, oldw, oldh);
		changeView();
		Log.i("Test", "newWidth is:" + w + "  newHeight is:" + h);
		Log.i("Test", "OLDWidth is:" + oldw + "  newHeight is:" + oldh);
		
	}

	/*
	 *	在view的大小产生变化时进行pic的重绘和位置重定位 ，保证在横屏和竖屏下都可以观看。
	 */
	private void changeView() {
			// TODO Auto-generated method stub

		if((float)getWidth()/(float)picWidth<(float)getHeight()/(float)picHeight){
			scale = (float)getWidth()/(float)picWidth;
			if (scale > 1) scale = 1;
			dy = -(getHeight()/scale-picHeight)/2;
			dx = -(getWidth()/scale-picWidth)/2;
		}else {
			scale = (float)getHeight()/(float)picHeight;
			if (scale > 1) { scale = 1; }
			dx = -(getWidth()/scale-picWidth)/2;
    		dy = -(getHeight()/scale-picHeight)/2;
		}
		invalidate();
	}

	/*    @Override
    protected void onDraw(Canvas canvas) {
        xRatio = getWidth() * 1.0f / picWidth;
        yRatio = getHeight() * 1.0f / picHeight;
        canvas.drawBitmap(sourceImage, null, new Rect(0, 0, getWidth(), getHeight()), tmpPaint);
   
        Paint pTemp1 = pDefault;
        for (int i = 0; i < eyesMidPts.length; i++) {
            if (eyesMidPts[i] != null) {
                if (i == mActionMoveIdx) {
                    pTemp1 = pMoving;
                } else if (i == mActionScaleIdx) {
                    pTemp1 = pScaling;
                } else {
                    pTemp1 = pDefault;
                }
                canvas.drawCircle(eyesMidPts[i].x * xRatio,
                        eyesMidPts[i].y * yRatio, 
                        eyesDistance[i] * xRatio * 2 ,
                        pTemp1);
                if (eyesPeopleNames[i] != null) {
                    canvas.drawText(eyesPeopleNames[i],
                            eyesMidPts[i].x * xRatio - eyesDistance[i] * xRatio,
                            eyesMidPts[i].y * yRatio - eyesDistance[i] * xRatio,
                            pTextLabel);
                }
                
//                canvas.drawRect(eyesMidPts[i].x * xRatio - eyesDistance[i] / 2,
//                        eyesMidPts[i].y * yRatio - eyesDistance[i] / 2,
//                        eyesMidPts[i].x * xRatio + eyesDistance[i] / 2,
//                        eyesMidPts[i].y * yRatio + eyesDistance[i] / 2,
//                        pOuterBullsEye);
                
//                canvas.drawCircle(eyesMidPts[i].x * xRatio, 
//                                  eyesMidPts[i].y * yRatio, 
//                                  eyesDistance[i] / 2,
//                                  pOuterBullsEye);
//                canvas.drawCircle(eyesMidPts[i].x * xRatio, 
//                                  eyesMidPts[i].y * yRatio, 
//                                  3/*eyesDistance[i] / 6,
//                                  pInnerBullsEye);
            }
        }
    }*/

    /**
     * @return true 增加成功 false 增加失败  功能尚未实现
     */
    public boolean addOneCircle() {
        for (int i = 0; i < eyesMidPts.length; i++) {
            if (eyesMidPts[i] == null) {
                eyesMidPts[i] = new PointF(getWidth()/2.0f/xRatio, getHeight()/2.0f/yRatio);
                eyesDistance[i] = getWidth()/16.0f/xRatio;
                this.invalidate();
                return true;
            }
        }
        return false;
    }
    
    /**
     * @return true 删除成功 false 删除失败  功能尚未实现
     */
    public boolean delOneCircle(int idx) {
        if (eyesMidPts[idx] != null) {
            eyesMidPts[idx] = null;
            eyesDistance[idx] = 0.0f;
            this.invalidate();
            return true;
        }
        return false;
    }
	
	
	/** 
	 * 两个触点间的直线距离 
	 */
    private float spacing(MotionEvent event) {
       float x = event.getX(0) - event.getX(1);
       float y = event.getY(0) - event.getY(1);
       return FloatMath.sqrt(x * x + y * y);
    }
    
	/** 
	 * 坐标点与眼的距离 
	 */
    private float disOfEyeCenter(float x, float y, int i) {
    	double dx = eyesMidPts[i].x - toRelativeCoordinates(x, y).x;
        double dy = eyesMidPts[i].y - toRelativeCoordinates(x, y).y;
        double dis = Math.sqrt((double)(dx*dx+dy*dy));
        return (float)dis;
    }
    
    /**
     * @param x
     * @param y
     * @param i
     * @return
     */
    private boolean isInEye(float x, float y, int i) {
    	double dis = disOfEyeCenter(x, y, i);
        double EyeDis = eyesDistance[i];
        return dis < EyeDis;
    }

    /**
     * @param x
     * @param y
     * @param i
     * @param delta = 50
     * @return
     */
    private boolean isNearEye2x(float x, float y, int i, int delta) {
        double dis = disOfEyeCenter(x, y, i);
        double EyeDis = eyesDistance[i]*2;
        return (dis < EyeDis+delta && dis > EyeDis-delta);
    }
    
    /**
     * 算出移动后的眼睛中心距离
     */
    
    
    private PointF newEyeCenter(float x, float y, int i)
    {
    	endPointF.set(x, y);
    	PointF eyeMidF = new PointF(eyesMidPts[i].x + (endPointF.x-startPointF.x)/scale,
    			eyesMidPts[i].y+ (endPointF.y-startPointF.y)/scale);
    	startPointF.set(x, y);
    	return eyeMidF;
    }
    
	/** 
	 * 将绝对坐标转换成sourceImage上的相对坐标点
	 */
	
    private PointF toRelativeCoordinates(float x, float y) 
	{
		return new PointF(this.dx+x/scale,this.dy+y/scale);
	}
	
	/** 
	 * 将sourceImage上的相对坐标点转换成整个view画布上的绝对坐标点
	 */

    private PointF toRawCoordinates(float x, float y) 
	{
		return new PointF((x-this.dx)*scale,(y-this.dy)*scale);
	}
	
	/** 
	 * 长按view引发的事件
	 */
    private boolean longPressdView(float x, float y)
	{
		for (int i = 0; i < eyesMidPts.length; i++) {
            if (eyesMidPts[i] != null) {

                if (isNearEye2x(x, y, i, 50)) {
                    mActionSelectedIdx = i;
                    mActionScaleIdx = i;
                    return true;
                } else if (isInEye(x, y, i)) {
                    mActionSelectedIdx = i;
                    mActionMoveIdx = i;
                    return true;
                }
            }
        }
		return false;

	}
	
	/** 
	 * 触摸view触发的事件
	 */
    private void touchView(MotionEvent event)
	{
		switch (event.getAction() & MotionEvent.ACTION_MASK) 
	    {
	    	case MotionEvent.ACTION_DOWN:
	        	Log.d(TAG, "mode=DRAG");
		        mode = DRAG;
		        startPointF.set(event.getX(),event.getY());
		        break;
	        case MotionEvent.ACTION_POINTER_DOWN:
	        	oldDist = spacing(event);
	        	Log.d(TAG, "oldDist=" + oldDist);
	        	if (oldDist > 10f) {
	        		mode = ZOOM;
	        		Log.d(TAG, "mode=ZOOM");
	        	}
	        	break;
	        case MotionEvent.ACTION_UP:
	        case MotionEvent.ACTION_POINTER_UP:
	        	mode = NONE;
	        	Log.d(TAG, "mode=NONE");
	        	if (mActionMoveIdx >= 0) {
	        		mActionMoveIdx = -1;
	        	} 
	        	else if (mActionScaleIdx >= 0) {
	        		mActionScaleIdx = -1;
	        	}
	        	invalidate();
	        	break;
	        case MotionEvent.ACTION_MOVE:
	        	if (mode == DRAG) {
	        		if (mActionMoveIdx >= 0) {
	  		  			eyesMidPts[mActionMoveIdx] = newEyeCenter(event.getX(),event.getY(),mActionMoveIdx);
	        			invalidate();
	        		   
	        	   } else if (mActionScaleIdx >= 0) {
	    	           float dis = disOfEyeCenter(event.getX(), event.getY(), mActionScaleIdx);
	    	           eyesDistance[mActionScaleIdx] = dis/2;
	    	           invalidate();
	    	       }
	           }
	           else if (mode == ZOOM) {
	              float newDist = spacing(event);
	              Log.d(TAG, "newDist=" + newDist);
	              if (newDist > 10f) {
	            	  scale *= newDist / oldDist*sensitive;
	            	  oldDist = newDist;//保证平滑过渡
	              }
	           }
	    	   
	    	   break;
	    }
	}

	/** 
	 * view发生偏移后引起的事件
	 */
    private void scrollView(float distanceX, float distanceY) {
		// TODO Auto-generated method stub
//		if(mode==ZOOM)
//        {
//        	dx = dx/scale;
//        	dy = dy/scale;
//        	invalidate();
//        }
//        else {
        	dx = toRelativeCoordinates(distanceX, distanceY).x;
            dy = toRelativeCoordinates(distanceX, distanceY).y;
            invalidate();	
//		}
	}
	
	/** 
	 * 单击后触发的事件
	 */
    private void singleTapUp(float x, float y) {
		
	}
	/** 
	 * 判断SourceImage是否移出了整个view，并为缩放设定了一个约束
	 */
    private void toLimitView(float min, float max) {
		// TODO Auto-generated method stub
    	if(scale < min)
    	{
    		scale = min;
    	}else if(scale > max){
    		scale = max;
    	}
    	
    	if(picWidth-getWidth()/scale>=0)
    	{
    		if(toRelativeCoordinates(0, 0).x < 0)
        	{
        		dx = 0;
        	}
        	if(toRelativeCoordinates(getWidth(), getHeight()).x > picWidth)
        	{
        		dx = picWidth-getWidth()/scale;
        	}
    	}else {
    		if(toRelativeCoordinates(0, 0).x >0)
    		{
    			dx = 0;
    		}
    		if(toRelativeCoordinates(getWidth(), getHeight()).x < picWidth)
    		{
        		dx = picWidth-getWidth()/scale;
    		}
		}
    	if(picHeight-getHeight()/scale>=0)
    	{
        	if(toRelativeCoordinates(0, 0).y < 0)
        	{
        		dy = 0;
        	}
        	if(toRelativeCoordinates(getWidth(), getHeight()).y > picHeight)
        	{
        		dy = picHeight-getHeight()/scale;
        	}
    	}else {
    		if(toRelativeCoordinates(0, 0).y >0)
    		{
    			dy = 0;
    		}
    		if(toRelativeCoordinates(getWidth(), getHeight()).y < picHeight)
    		{
        		dy = picHeight-getHeight()/scale;
    		}
		}
	}
    
	/** 
	 * 对图像进行脸部检测。
	 */
    public void faceDetect() {
    	arrayFaces = new FaceDetector(picWidth, picHeight, NUM_FACES);
        arrayFaces.findFaces(sourceImage, getAllFaces);
        
        for (int i = 0; i < getAllFaces.length; i++) {
            getFace = getAllFaces[i];
            try {
                PointF eyesMP = new PointF();
                getFace.getMidPoint(eyesMP);
                eyesDistance[i] = getFace.eyesDistance();
                eyesMidPts[i] = eyesMP;

                if (DEBUG) {
                    Log.i("Face", 
                          i + " " + getFace.confidence() + " " + getFace.eyesDistance() + " " + "Pose: ("
                          + getFace.pose(FaceDetector.Face.EULER_X) + ","
                          + getFace.pose(FaceDetector.Face.EULER_Y) + ","
                          + getFace.pose(FaceDetector.Face.EULER_Z) + ")" + "Eyes Midpoint: ("
                          + eyesMidPts[i].x + "," + eyesMidPts[i].y + ")");
                }
            } catch (Exception e) {
                if (DEBUG) Log.e("Face", i + " is null");
            }
        }
	}

    
    /** 
	 * Touch到这个view时触发。
	 */
    @Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
    	touchView(event);
    	return mGd.onTouchEvent(event); 
//		super.onTouchEvent(event);
	}

    /** 
	 * Touch down时触发。
	 */
	@Override
	public boolean onDown(MotionEvent event) {
		// TODO Auto-generated method stub
		return true;
	}

	/** 
	 * Touch了滑动一点距离后，up时触发。
	 */
	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {
		// TODO Auto-generated method stub
		return true;
	}

	/** 
	 * Touch了不移动一直Touch down时触发
	 */
	@Override
	public void onLongPress(MotionEvent event) {
		// TODO Auto-generated method stub
		if(true==longPressdView(event.getX(), event.getY()))
        {
        	Vibrator vibrator = (Vibrator)context.getSystemService(
                    Context.VIBRATOR_SERVICE);
            vibrator.vibrate(50);
        }
	}

	/** 
	 * Touch了滑动时触发。
	 */
	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		// TODO Auto-generated method stub
		scrollView(distanceX,distanceY); 
		return true;
	}

	/** 
	 * Touch了还没有滑动时触发。
	 */
	@Override
	public void onShowPress(MotionEvent event) {
		// TODO Auto-generated method stub
		
	}

	/** 
	 * touch down后又没有滑动（onScroll），又没有长按（onLongPress），然后Touchup时触发。
	 */
	@Override
	public boolean onSingleTapUp(MotionEvent event) {
		// TODO Auto-generated method stub
		singleTapUp(event.getX(),event.getY());
		return true;
	}


}

